﻿using Enterprises.Wpf.Core.Attributes;
using Enterprises.Wpf.Core.Common;
using Enterprises.Wpf.Core.Entity;
using Enterprises.Wpf.Core.Enums;
using Enterprises.Wpf.Core.Helper;
using Enterprises.Wpf.Core.Localization;
using Enterprises.Wpf.Core.Net;

namespace Enterprises.Wpf.Core.Modbus
{
    /// <summary>
    /// Modbus-Udp协议的客户端通讯类，方便的和服务器进行数据交互，支持标准的功能码，也支持扩展的功能码实现，地址采用富文本的形式，详细见备注说明<br />
    /// The client communication class of Modbus-Udp protocol is convenient for data interaction with the server. It supports standard function codes and also supports extended function codes. 
    /// The address is in rich text. For details, see the remarks.
    /// </summary>
    /// <remarks>
    /// 本客户端支持的标准的modbus协议，Modbus-Tcp及Modbus-Udp内置的消息号会进行自增，地址支持富文本格式，具体参考示例代码。<br />
    /// 读取线圈，输入线圈，寄存器，输入寄存器的方法中的读取长度对商业授权用户不限制，内部自动切割读取，结果合并。
    /// </remarks>
    /// <example>
    /// <inheritdoc cref="T:HslCommunication.ModBus.ModbusTcpNet" path="example" />
    /// </example>
    public class ModbusUdpNet : NetworkUdpDeviceBase, IModbus, IReadWriteDevice, IReadWriteNet
    {
        private byte station = 1;

        private SoftIncrementCount softIncrementCount;

        private bool isAddressStartWithZero = true;

        /// <inheritdoc cref="P:HslCommunication.ModBus.ModbusTcpNet.AddressStartWithZero" />
        public bool AddressStartWithZero
        {
            get
            {
                return isAddressStartWithZero;
            }
            set
            {
                isAddressStartWithZero = value;
            }
        }

        /// <inheritdoc cref="P:HslCommunication.ModBus.ModbusTcpNet.Station" />
        public byte Station
        {
            get
            {
                return station;
            }
            set
            {
                station = value;
            }
        }

        public DataFormat DataFormat
        {
            get
            {
                return base.ByteTransform.DataFormat;
            }
            set
            {
                base.ByteTransform.DataFormat = value;
            }
        }

        public bool IsStringReverse
        {
            get
            {
                return base.ByteTransform.IsStringReverseByteWord;
            }
            set
            {
                base.ByteTransform.IsStringReverseByteWord = value;
            }
        }

        /// <inheritdoc cref="P:HslCommunication.ModBus.ModbusTcpNet.MessageId" />
        public SoftIncrementCount MessageId => softIncrementCount;

        /// <summary>
        /// 实例化一个MOdbus-Udp协议的客户端对象<br />
        /// Instantiate a client object of the MOdbus-Udp protocol
        /// </summary>
        public ModbusUdpNet()
        {
            base.ByteTransform = new ReverseWordTransform();
            softIncrementCount = new SoftIncrementCount(65535L, 0L);
            base.WordLength = 1;
        }

        /// <inheritdoc cref="M:HslCommunication.ModBus.ModbusTcpNet.#ctor(System.String,System.Int32,System.Byte)" />
        public ModbusUdpNet(string ipAddress, int port = 502, byte station = 1)
            : this()
        {
            IpAddress = ipAddress;
            Port = port;
            this.station = station;
        }

        /// <inheritdoc cref="M:HslCommunication.ModBus.IModbus.TranslateToModbusAddress(System.String,System.Byte)" />
        public virtual OperateResult<string> TranslateToModbusAddress(string address, byte modbusCode)
        {
            return OperateResult.CreateSuccessResult(address);
        }

        /// <inheritdoc />
        public override byte[] PackCommandWithHeader(byte[] command)
        {
            return ModbusInfo.PackCommandToTcp(command, (ushort)softIncrementCount.GetCurrentValue());
        }

        /// <inheritdoc />
        public override OperateResult<byte[]> UnpackResponseContent(byte[] send, byte[] response)
        {
            if (response == null || response.Length < 6)
            {
                return new OperateResult<byte[]>(StringResources.Language.ReceiveDataLengthTooShort + " Content: " + response.ToHexString(' '));
            }
            return ModbusInfo.ExtractActualData(ModbusInfo.ExplodeTcpCommandToCore(response));
        }

        /// <inheritdoc cref="M:HslCommunication.ModBus.ModbusTcpNet.ReadCoil(System.String)" />
        public OperateResult<bool> ReadCoil(string address)
        {
            return ReadBool(address);
        }

        /// <inheritdoc cref="M:HslCommunication.ModBus.ModbusTcpNet.ReadCoil(System.String,System.UInt16)" />
        public OperateResult<bool[]> ReadCoil(string address, ushort length)
        {
            return ReadBool(address, length);
        }

        /// <inheritdoc cref="M:HslCommunication.ModBus.ModbusTcpNet.ReadDiscrete(System.String)" />
        public OperateResult<bool> ReadDiscrete(string address)
        {
            return ByteTransformHelper.GetResultFromArray(ReadDiscrete(address, 1));
        }

        /// <inheritdoc cref="M:HslCommunication.ModBus.ModbusUdpNet.ReadDiscrete(System.String,System.UInt16)" />
        public OperateResult<bool[]> ReadDiscrete(string address, ushort length)
        {
            return ModbusHelper.ReadBoolHelper(this, address, length, 2);
        }

        /// <inheritdoc cref="M:HslCommunication.ModBus.ModbusTcpNet.Read(System.String,System.UInt16)" />
        public override OperateResult<byte[]> Read(string address, ushort length)
        {
            return ModbusHelper.Read(this, address, length);
        }

        /// <inheritdoc cref="M:HslCommunication.ModBus.ModbusHelper.ReadWrite(HslCommunication.ModBus.IModbus,System.String,System.UInt16,System.String,System.Byte[])" />
        public OperateResult<byte[]> ReadWrite(string readAddress, ushort length, string writeAddress, byte[] value)
        {
            return ModbusHelper.ReadWrite(this, readAddress, length, writeAddress, value);
        }

        /// <inheritdoc cref="M:HslCommunication.ModBus.ModbusTcpNet.Write(System.String,System.Byte[])" />
        public override OperateResult Write(string address, byte[] value)
        {
            return ModbusHelper.Write(this, address, value);
        }

        /// <inheritdoc cref="M:HslCommunication.ModBus.ModbusTcpNet.Write(System.String,System.Int16)" />
        public override OperateResult Write(string address, short value)
        {
            return ModbusHelper.Write(this, address, value);
        }

        /// <inheritdoc cref="M:HslCommunication.ModBus.ModbusTcpNet.Write(System.String,System.UInt16)" />
        public override OperateResult Write(string address, ushort value)
        {
            return ModbusHelper.Write(this, address, value);
        }

        /// <inheritdoc cref="M:HslCommunication.ModBus.ModbusTcpNet.WriteMask(System.String,System.UInt16,System.UInt16)" />
        public OperateResult WriteMask(string address, ushort andMask, ushort orMask)
        {
            return ModbusHelper.WriteMask(this, address, andMask, orMask);
        }

        /// <inheritdoc cref="M:HslCommunication.ModBus.ModbusTcpNet.WriteOneRegister(System.String,System.Int16)" />
        public OperateResult WriteOneRegister(string address, short value)
        {
            return Write(address, value);
        }

        /// <inheritdoc cref="M:HslCommunication.ModBus.ModbusTcpNet.WriteOneRegister(System.String,System.UInt16)" />
        public OperateResult WriteOneRegister(string address, ushort value)
        {
            return Write(address, value);
        }

        /// <inheritdoc cref="M:HslCommunication.ModBus.ModbusTcpNet.ReadCoilAsync(System.String)" />
        public async Task<OperateResult<bool>> ReadCoilAsync(string address)
        {
            return await Task.Run(() => ReadCoil(address));
        }

        /// <inheritdoc cref="M:HslCommunication.ModBus.ModbusTcpNet.ReadCoilAsync(System.String,System.UInt16)" />
        public async Task<OperateResult<bool[]>> ReadCoilAsync(string address, ushort length)
        {
            return await Task.Run(() => ReadCoil(address, length));
        }

        /// <inheritdoc cref="M:HslCommunication.ModBus.ModbusTcpNet.ReadDiscreteAsync(System.String)" />
        public async Task<OperateResult<bool>> ReadDiscreteAsync(string address)
        {
            return await Task.Run(() => ReadDiscrete(address));
        }

        /// <inheritdoc cref="M:HslCommunication.ModBus.ModbusTcpNet.ReadDiscreteAsync(System.String,System.UInt16)" />
        public async Task<OperateResult<bool[]>> ReadDiscreteAsync(string address, ushort length)
        {
            return await Task.Run(() => ReadDiscrete(address, length));
        }

        /// <inheritdoc cref="M:HslCommunication.ModBus.ModbusUdpNet.Write(System.String,System.Int16)" />/param&gt;
        public override async Task<OperateResult> WriteAsync(string address, short value)
        {
            return await Task.Run(() => Write(address, value));
        }

        /// <inheritdoc cref="M:HslCommunication.ModBus.ModbusUdpNet.Write(System.String,System.UInt16)" />/param&gt;
        public override async Task<OperateResult> WriteAsync(string address, ushort value)
        {
            return await Task.Run(() => Write(address, value));
        }

        /// <inheritdoc cref="M:HslCommunication.ModBus.ModbusTcpNet.WriteOneRegister(System.String,System.Int16)" />
        public async Task<OperateResult> WriteOneRegisterAsync(string address, short value)
        {
            return await Task.Run(() => WriteOneRegister(address, value));
        }

        /// <inheritdoc cref="M:HslCommunication.ModBus.ModbusTcpNet.WriteOneRegister(System.String,System.UInt16)" />
        public async Task<OperateResult> WriteOneRegisterAsync(string address, ushort value)
        {
            return await Task.Run(() => WriteOneRegister(address, value));
        }

        /// <inheritdoc cref="M:HslCommunication.ModBus.ModbusTcpNet.WriteMask(System.String,System.UInt16,System.UInt16)" />
        public async Task<OperateResult> WriteMaskAsync(string address, ushort andMask, ushort orMask)
        {
            return await Task.Run(() => WriteMask(address, andMask, orMask));
        }

        public override OperateResult<bool[]> ReadBool(string address, ushort length)
        {
            return ModbusHelper.ReadBoolHelper(this, address, length, 1);
        }

        public override OperateResult Write(string address, bool[] values)
        {
            return ModbusHelper.Write(this, address, values);
        }

        public override OperateResult Write(string address, bool value)
        {
            return ModbusHelper.Write(this, address, value);
        }

        /// <inheritdoc cref="M:HslCommunication.ModBus.ModbusTcpNet.WriteAsync(System.String,System.Boolean)" />
        public override async Task<OperateResult> WriteAsync(string address, bool value)
        {
            return await Task.Run(() => Write(address, value));
        }

        public override OperateResult<int[]> ReadInt32(string address, ushort length)
        {
            IByteTransform transform = HslHelper.ExtractTransformParameter(ref address, base.ByteTransform);
            return ByteTransformHelper.GetResultFromBytes(Read(address, (ushort)(length * base.WordLength * 2)), (byte[] m) => transform.TransInt32(m, 0, length));
        }

        public override OperateResult<uint[]> ReadUInt32(string address, ushort length)
        {
            IByteTransform transform = HslHelper.ExtractTransformParameter(ref address, base.ByteTransform);
            return ByteTransformHelper.GetResultFromBytes(Read(address, (ushort)(length * base.WordLength * 2)), (byte[] m) => transform.TransUInt32(m, 0, length));
        }

        public override OperateResult<float[]> ReadFloat(string address, ushort length)
        {
            IByteTransform transform = HslHelper.ExtractTransformParameter(ref address, base.ByteTransform);
            return ByteTransformHelper.GetResultFromBytes(Read(address, (ushort)(length * base.WordLength * 2)), (byte[] m) => transform.TransSingle(m, 0, length));
        }

        public override OperateResult<long[]> ReadInt64(string address, ushort length)
        {
            IByteTransform transform = HslHelper.ExtractTransformParameter(ref address, base.ByteTransform);
            return ByteTransformHelper.GetResultFromBytes(Read(address, (ushort)(length * base.WordLength * 4)), (byte[] m) => transform.TransInt64(m, 0, length));
        }

        /// <inheritdoc cref="M:HslCommunication.Core.IReadWriteNet.ReadUInt64(System.String,System.UInt16)" />
        [HslMqttApi("ReadUInt64Array", "")]
        public override OperateResult<ulong[]> ReadUInt64(string address, ushort length)
        {
            IByteTransform transform = HslHelper.ExtractTransformParameter(ref address, base.ByteTransform);
            return ByteTransformHelper.GetResultFromBytes(Read(address, (ushort)(length * base.WordLength * 4)), (byte[] m) => transform.TransUInt64(m, 0, length));
        }

        /// <inheritdoc cref="M:HslCommunication.Core.IReadWriteNet.ReadDouble(System.String,System.UInt16)" />
        [HslMqttApi("ReadDoubleArray", "")]
        public override OperateResult<double[]> ReadDouble(string address, ushort length)
        {
            IByteTransform transform = HslHelper.ExtractTransformParameter(ref address, base.ByteTransform);
            return ByteTransformHelper.GetResultFromBytes(Read(address, (ushort)(length * base.WordLength * 4)), (byte[] m) => transform.TransDouble(m, 0, length));
        }

        /// <inheritdoc cref="M:HslCommunication.Core.IReadWriteNet.Write(System.String,System.Int32[])" />
        [HslMqttApi("WriteInt32Array", "")]
        public override OperateResult Write(string address, int[] values)
        {
            IByteTransform byteTransform = HslHelper.ExtractTransformParameter(ref address, base.ByteTransform);
            return Write(address, byteTransform.TransByte(values));
        }

        /// <inheritdoc cref="M:HslCommunication.Core.IReadWriteNet.Write(System.String,System.UInt32[])" />
        [HslMqttApi("WriteUInt32Array", "")]
        public override OperateResult Write(string address, uint[] values)
        {
            IByteTransform byteTransform = HslHelper.ExtractTransformParameter(ref address, base.ByteTransform);
            return Write(address, byteTransform.TransByte(values));
        }

        /// <inheritdoc cref="M:HslCommunication.Core.IReadWriteNet.Write(System.String,System.Single[])" />
        [HslMqttApi("WriteFloatArray", "")]
        public override OperateResult Write(string address, float[] values)
        {
            IByteTransform byteTransform = HslHelper.ExtractTransformParameter(ref address, base.ByteTransform);
            return Write(address, byteTransform.TransByte(values));
        }

        /// <inheritdoc cref="M:HslCommunication.Core.IReadWriteNet.Write(System.String,System.Int64[])" />
        [HslMqttApi("WriteInt64Array", "")]
        public override OperateResult Write(string address, long[] values)
        {
            IByteTransform byteTransform = HslHelper.ExtractTransformParameter(ref address, base.ByteTransform);
            return Write(address, byteTransform.TransByte(values));
        }

        /// <inheritdoc cref="M:HslCommunication.Core.IReadWriteNet.Write(System.String,System.UInt64[])" />
        [HslMqttApi("WriteUInt64Array", "")]
        public override OperateResult Write(string address, ulong[] values)
        {
            IByteTransform byteTransform = HslHelper.ExtractTransformParameter(ref address, base.ByteTransform);
            return Write(address, byteTransform.TransByte(values));
        }

        /// <inheritdoc cref="M:HslCommunication.Core.IReadWriteNet.Write(System.String,System.Double[])" />
        [HslMqttApi("WriteDoubleArray", "")]
        public override OperateResult Write(string address, double[] values)
        {
            IByteTransform byteTransform = HslHelper.ExtractTransformParameter(ref address, base.ByteTransform);
            return Write(address, byteTransform.TransByte(values));
        }

        /// <inheritdoc cref="M:HslCommunication.Core.IReadWriteNet.ReadInt32Async(System.String,System.UInt16)" />
        public override async Task<OperateResult<int[]>> ReadInt32Async(string address, ushort length)
        {
            IByteTransform transform = HslHelper.ExtractTransformParameter(ref address, base.ByteTransform);
            return ByteTransformHelper.GetResultFromBytes(await ReadAsync(address, (ushort)(length * base.WordLength * 2)), (byte[] m) => transform.TransInt32(m, 0, length));
        }

        /// <inheritdoc cref="M:HslCommunication.Core.IReadWriteNet.ReadUInt32Async(System.String,System.UInt16)" />
        public override async Task<OperateResult<uint[]>> ReadUInt32Async(string address, ushort length)
        {
            IByteTransform transform = HslHelper.ExtractTransformParameter(ref address, base.ByteTransform);
            return ByteTransformHelper.GetResultFromBytes(await ReadAsync(address, (ushort)(length * base.WordLength * 2)), (byte[] m) => transform.TransUInt32(m, 0, length));
        }

        /// <inheritdoc cref="M:HslCommunication.Core.IReadWriteNet.ReadFloatAsync(System.String,System.UInt16)" />
        public override async Task<OperateResult<float[]>> ReadFloatAsync(string address, ushort length)
        {
            IByteTransform transform = HslHelper.ExtractTransformParameter(ref address, base.ByteTransform);
            return ByteTransformHelper.GetResultFromBytes(await ReadAsync(address, (ushort)(length * base.WordLength * 2)), (byte[] m) => transform.TransSingle(m, 0, length));
        }

        /// <inheritdoc cref="M:HslCommunication.Core.IReadWriteNet.ReadInt64Async(System.String,System.UInt16)" />
        public override async Task<OperateResult<long[]>> ReadInt64Async(string address, ushort length)
        {
            IByteTransform transform = HslHelper.ExtractTransformParameter(ref address, base.ByteTransform);
            return ByteTransformHelper.GetResultFromBytes(await ReadAsync(address, (ushort)(length * base.WordLength * 4)), (byte[] m) => transform.TransInt64(m, 0, length));
        }

        /// <inheritdoc cref="M:HslCommunication.Core.IReadWriteNet.ReadUInt64Async(System.String,System.UInt16)" />
        public override async Task<OperateResult<ulong[]>> ReadUInt64Async(string address, ushort length)
        {
            IByteTransform transform = HslHelper.ExtractTransformParameter(ref address, base.ByteTransform);
            return ByteTransformHelper.GetResultFromBytes(await ReadAsync(address, (ushort)(length * base.WordLength * 4)), (byte[] m) => transform.TransUInt64(m, 0, length));
        }

        /// <inheritdoc cref="M:HslCommunication.Core.IReadWriteNet.ReadDoubleAsync(System.String,System.UInt16)" />
        public override async Task<OperateResult<double[]>> ReadDoubleAsync(string address, ushort length)
        {
            IByteTransform transform = HslHelper.ExtractTransformParameter(ref address, base.ByteTransform);
            return ByteTransformHelper.GetResultFromBytes(await ReadAsync(address, (ushort)(length * base.WordLength * 4)), (byte[] m) => transform.TransDouble(m, 0, length));
        }

        /// <inheritdoc cref="M:HslCommunication.Core.IReadWriteNet.WriteAsync(System.String,System.Int32[])" />
        public override async Task<OperateResult> WriteAsync(string address, int[] values)
        {
            return await WriteAsync(value: HslHelper.ExtractTransformParameter(ref address, base.ByteTransform).TransByte(values), address: address);
        }

        /// <inheritdoc cref="M:HslCommunication.Core.IReadWriteNet.WriteAsync(System.String,System.UInt32[])" />
        public override async Task<OperateResult> WriteAsync(string address, uint[] values)
        {
            return await WriteAsync(value: HslHelper.ExtractTransformParameter(ref address, base.ByteTransform).TransByte(values), address: address);
        }

        /// <inheritdoc cref="M:HslCommunication.Core.IReadWriteNet.WriteAsync(System.String,System.Single[])" />
        public override async Task<OperateResult> WriteAsync(string address, float[] values)
        {
            return await WriteAsync(value: HslHelper.ExtractTransformParameter(ref address, base.ByteTransform).TransByte(values), address: address);
        }

        /// <inheritdoc cref="M:HslCommunication.Core.IReadWriteNet.WriteAsync(System.String,System.Int64[])" />
        public override async Task<OperateResult> WriteAsync(string address, long[] values)
        {
            return await WriteAsync(value: HslHelper.ExtractTransformParameter(ref address, base.ByteTransform).TransByte(values), address: address);
        }

        /// <inheritdoc cref="M:HslCommunication.Core.IReadWriteNet.WriteAsync(System.String,System.UInt64[])" />
        public override async Task<OperateResult> WriteAsync(string address, ulong[] values)
        {
            return await WriteAsync(value: HslHelper.ExtractTransformParameter(ref address, base.ByteTransform).TransByte(values), address: address);
        }

        /// <inheritdoc cref="M:HslCommunication.Core.IReadWriteNet.WriteAsync(System.String,System.Double[])" />
        public override async Task<OperateResult> WriteAsync(string address, double[] values)
        {
            return await WriteAsync(value: HslHelper.ExtractTransformParameter(ref address, base.ByteTransform).TransByte(values), address: address);
        }

        /// <inheritdoc />
        public override string ToString()
        {
            return $"ModbusUdpNet[{IpAddress}:{Port}]";
        }
    }

}
